The Component Object Model (COM) is a software architecture that supports reuse of software components between different application programs written in different languages. Reusing software components, where appropriate, reduces the cost of creating a new application as compared to creating an application from scratch. COM addresses the issues of interoperability where reuse is desirable for binary executables that are created by different entities in different languages.
In COM, a “component” is a piece of compiled code that provides one or more services. It will be appreciated that even though a component is also an object in object oriented programming (OOP) terms, the term “component” will be used herein to avoid confusion with other objects in general. An “interface” is the mechanism through which components interact and through which software in general accesses the services of a component. The interface defines the behavior and responsibilities of the component. In other words, the interface is a group of related functions and forms the binary standard or contract through which the component is accessed.
A COM interface is not a class and cannot be instantiated by itself. A COM component must implement the interface, and the component must be instantiated for the interface to exist. It will be appreciated that the same interface can be implemented in different ways by different components with the restriction that each component must satisfy the interface's behavior and responsibilities. The information presented above, along with a more detailed explanation, is found in “Dr. Dobbs Journal”, December 1994.
Sometimes it is desirable to implement a hierarchy of interfaces, which is often accompanied by a parallel class hierarchy, for example in C++. In implementing the component(s) behind the interfaces, ambiguity may result between certain method calls. Delegation is generally the method used to resolve ambiguity.
The problem is illustrated with the following example COM interface hierarchy:
interface IAnimal : IUnknown{HRESULT eat( );};interface IPerson : IAnimal{HRESULT talk( );};interface IEmployee : IPerson{HRESULT work( );};
The hierarchy includes three interfaces: IAnimal, IPerson, and IEmployee. Interface IAnimal is a type of the base interface, IUnknown, which is provided by COM; interface IPerson is a type of the IAnimal interface; and interface IEmployee is a type of IPerson interface. Interface IAnimal has a member method, eat( ); interface IPerson has a member method, talk( ); and interface IEmployee has a member method, work( ).
A parallel class hierarchy is often desirable when implementing such an interface hierarchy. Such a design allows the implementation of a given interface to be totally encapsulated by a single class. Initially consideration of implementing the above interface hierarchy in C++ leads to the following parallel class hierarchy:
typedef someType TStatus;class CAnimal{virtual TStatus eat( ){ . . . }};class CPerson : public CAnimal{virtual TStatus talk( ){ . . . }};class CEmployee : public CPerson{virtual TStatus work( ){ . . . }};The C++ access specifications (public, private, and protected) have been omitted to enhance readability. It can be seen that the classes CAnimal, CPerson, and CEmployee parallel the interfaces IAnimal, IPerson, and IEmployee in terms of inheritance and method definitions. The virtual methods eat( ), talk( ), and work( ) are included in the classes CAnimal, CPerson, and CEmployee, respectively.
To implement the interface hierarchy along with the COM components, a C++ implementation begins with incorporation of the COM interface. Thus, the IAnimal interface may be implemented as:
class CComAnimal: public IAnimal{STDMETHOD( eat ) ( ){ . . . }};
At this juncture, IAnimal defines an abstract method eat( ), which has a concrete implementation in CComAnimal. It will be appreciated that STDMETHOD is a commonly used C++ preprocessor macro within the Microsoft C++ environment. The STDMETHOD( ) macro defines the standard calling convention and return type for a COM interface method.
The following code shows analogous concrete implementations of the IPerson and IEmployee interfaces:
class CComPerson: public IPerson, public CComAnimal{STDMETHOD( talk ) ( ){ . . . }};class CComEmployee: public IEmployee, public CComPerson{STDMETHOD( work ) ( ){ . . . }};It will be appreciated that if the foregoing code is left as is, the multiple inheritance introduced from both IPerson and CComAnimal makes referencing the method CComPerson::eat( )ambiguous. That is, CComPerson::eat( ) may be in reference to eat( ) of interface IAnimal (by virtue of inheritance from IPerson) or in reference to eat( ) of class CComAnimal. A similar ambiguity exists between eat( ) and talk( ) as defined in CComPerson and eat( ) and talk( ) as declared in IEmployee. Thus, using delegation, the ambiguity is resolved with the following example code:
class CComPerson: public IPerson, public CComAnimal{STDMETHOD( eat ) ( ){ return CComAnimal::eat( ); }STDMETHOD( talk ) ( ){ . . . }};class CComEmployee: public IEmployee, public CComPerson{STDMETHOD( eat ) ( ){ return CComPerson::eat( ); }STDMETHOD( talk ) ( ){ return CComPerson::talk( ); }STDMETHOD ( work ) ( ){ . . . }};
At this point, a C++ class implementation hierarchy has been defined that parallels the COM interface hierarchy. If the interfaces IAnimal, IPerson, and IEmployee had additional methods, then additional delegation code would be required. Furthermore, if the interface hierarchy had been deeper, more delegation code would be needed. While the delegation code provides a functioning implementation, understanding the implementation from a developer's point of view may be difficult because of the complex inheritance relationships and the representation in an object diagram.
FIG. 1 is an object model diagram that illustrates the class relationships of the class definitions set forth in the preceding code. It can be seen from the diagram that some of the classes inherit from two classes. For example, the CComEmployee class inherits from the CComPerson class and IEmployee interface. In addition, the IEmployee interface inherits from the CComAnimal class and the IPerson interface.
A method that addresses the aforementioned problems, as well as other related problems, is therefore desirable.